home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / test / testbtree.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  16.9 KB  |  743 lines

  1. /* ----------------------------------------------------------------
  2.  * testbtree.c --
  3.  *    B-tree test code.
  4.  * ----------------------------------------------------------------
  5.  */
  6.  
  7. #include "fmgr.h"    /* for M_STATIC/M_DYNAMIC */
  8.  
  9. #include <stdio.h>
  10.  
  11. #include "c.h"
  12.  
  13. #include "attnum.h"
  14. #include "attval.h"
  15. #include "bufmgr.h"
  16. #include "catname.h"
  17. #include "datum.h"
  18. #include "log.h"
  19. #include "genam.h"
  20. #include "heapam.h"
  21. #include "itemptr.h"
  22. #include "istrat.h"
  23. #include "itup.h"
  24. #include "name.h"
  25. #include "oid.h"
  26. #include "portal.h"
  27. #include "sdir.h"
  28. #include "tqual.h"
  29. #include "valid.h"
  30. #include "xcxt.h"
  31.  
  32. #include "btree.h"
  33.  
  34. RcsId("$Header: /private/postgres/src/test/RCS/testbtree.c,v 1.16 1992/03/04 14:10:47 hong Exp $");
  35.  
  36. /* ----------------
  37.  *    constants
  38.  * ----------------
  39.  */
  40.  
  41. #define UninitializedQualification    0
  42. #define SingleQualification        1
  43. #define DoubleQualification        2
  44. #define MarkedQualification        3
  45.  
  46. #define MarkedTuplesToProcess        64
  47.  
  48. static int        QualificationState;
  49. ScanKeyEntryData    QualificationKeyData[2];
  50.  
  51. AttributeNumber        indexAttrNumber;
  52. ObjectId         indexAttrClass;
  53.  
  54. /* ----------------------------------------------------------------
  55.  *               misc functions
  56.  * ----------------------------------------------------------------
  57.  */
  58.  
  59. /* ----------------
  60.  *    DoCreateIndex
  61.  * ----------------
  62.  */
  63.  
  64. void FUNCTION
  65.    DoCreateIndex(heapName, indexName, attribute, cls)
  66. Name        heapName;
  67. Name        indexName;
  68. AttributeNumber attribute;
  69. ObjectId    cls;
  70. {
  71.    AttributeNumber  attributeNumber[1];
  72.    ObjectId        attributeClass[1];
  73.  
  74.    elog(NOTICE, "DoCreateIndex... start");
  75.  
  76.    attributeNumber[0] = attribute;
  77.    attributeClass[0] =  cls;
  78.  
  79.    RelationNameCreateIndexRelation(heapName,
  80.                    indexName,
  81.                    400 /* B-tree AM */,
  82.                    1,
  83.                    attributeNumber,
  84.                    attributeClass,
  85.                    0,
  86.                    (Datum *) NULL);
  87.    fflush(stdout);
  88.    fflush(stderr);
  89.    elog(NOTICE, "DoCreateIndex... end");
  90.  
  91. }
  92.  
  93. /* ----------------
  94.  *    ShowResult
  95.  * ----------------
  96.  */
  97.  
  98. void FUNCTION
  99.    ShowResult(result, heapRelation)
  100. GeneralRetrieveIndexResult    result;
  101. Relation            heapRelation;
  102. {
  103.    ItemPointer    pointer;
  104.  
  105.    Assert(GeneralRetrieveIndexResultIsValid(result));
  106.  
  107.    pointer = GeneralRetrieveIndexResultGetHeapItemPointer(result);
  108.  
  109.    printf("\t");
  110.  
  111.    if (!ItemPointerIsValid(pointer)) {
  112.       printf("<invalid>\n");
  113.    } else {
  114.       HeapTuple    tuple;
  115.       Buffer    buffer;
  116.  
  117.       printf("[b,p,o %d, %d, %3d] ",
  118.          ItemPointerGetBlockNumber(pointer),
  119.          ItemPointerSimpleGetPageNumber(pointer),
  120.          ItemPointerSimpleGetOffsetNumber(pointer));
  121.  
  122.       tuple =
  123.      RelationGetHeapTupleByItemPointer(heapRelation,
  124.             NowTimeQual,
  125.                        pointer,
  126.                        &buffer);
  127.  
  128.       if (!HeapTupleIsValid(tuple)) {
  129.      printf("*NULL*\n");
  130.  
  131.       } else {
  132.      TupleDescriptor    descriptor;
  133.      AttributeValue        value;
  134.      Boolean        valueIsNull;
  135.  
  136.      descriptor = RelationGetTupleDescriptor(heapRelation);
  137.  
  138.      /* We might want to print more than just the index att, here */
  139.      value =
  140.         HeapTupleGetAttributeValue(tuple,
  141.                        buffer,
  142.                        indexAttrNumber,
  143.                        descriptor,
  144.                        &valueIsNull);
  145.  
  146.      if (valueIsNull) {
  147.         printf("<NULL>\n");
  148.      } else {
  149.         printf("<0x%x(%d)>\n",
  150.            DatumGetObjectId(value), 
  151.            DatumGetObjectId(value));
  152.      }
  153.  
  154.      ReleaseBuffer(buffer);
  155.       }
  156.    }
  157. }
  158.  
  159. /* ----------------
  160.  *    ShowScanKeyEntry
  161.  * ----------------
  162.  */
  163.  
  164. void FUNCTION
  165.    ShowScanKeyEntry(entry)
  166. ScanKeyEntry    entry;
  167. {
  168.    printf("Qualification is procedure 0x%x(%d) for %d with 0x%x\n",
  169.       entry->procedure,
  170.       entry->procedure,
  171.       DatumGetObjectId(entry->argument),
  172.       entry->flags);
  173. }
  174.  
  175. /* ----------------------------------------------------------------
  176.  *            browse functions
  177.  * ----------------------------------------------------------------
  178.  */
  179.  
  180. /* ----------------
  181.  *    DoBTreeBrowse
  182.  * ----------------
  183.  */
  184.  
  185. /*ARGSUSED*/
  186. void FUNCTION
  187.    DoBTreeBrowse(indexRelation, heapRelation)
  188. Relation    indexRelation;
  189. Relation    heapRelation;
  190. {
  191.    BTreeNode   node;
  192.    BlockNumber blockNumber;
  193.    PageNumber  pageNumber;
  194.    int cnt;
  195.  
  196.    puts("\n--- BTree Browse ---");
  197.    puts("at the prompt, enter a block number and a page number");
  198.    puts("separated by a space or \".\" alone to end\n");
  199.  
  200.    forever {
  201.       Puts("browse> ");
  202.       fflush(stdout);
  203.  
  204.       cnt = scanf("%ld %hd", &blockNumber, &pageNumber);
  205.       if (cnt != 2) {
  206.      puts("\n--- ending BTree Browse ---");
  207.      fseek(stdin, 0, 2);
  208.      break;
  209.       }
  210.  
  211.       node = RelationFormBTreeNode(indexRelation, blockNumber, pageNumber);
  212.       DumpBTreeNode(node);
  213.       BTreeNodeFree(node);
  214.       putchar('\n');
  215.    }
  216. }
  217.  
  218. /* ----------------------------------------------------------------
  219.  *              scan functions
  220.  * ----------------------------------------------------------------
  221.  */
  222.  
  223. /* ----------------
  224.  *    DoForwardScan
  225.  * ----------------
  226.  */
  227.  
  228. void FUNCTION
  229.    DoForwardScan(indexRelation, heapRelation)
  230. Relation    indexRelation;
  231. Relation    heapRelation;
  232. {
  233.    IndexScanDesc        scan;
  234.    GeneralRetrieveIndexResult    result;
  235.  
  236.    puts("A complete forward scan of the index reveals...");
  237.  
  238.    scan = RelationGetIndexScan(indexRelation, 0, 0, (ScanKey) NULL);
  239.  
  240.    for (;;) {
  241.       result = AMgettuple(scan, 1);
  242.  
  243.       if (!GeneralRetrieveIndexResultIsValid(result))
  244.      break;
  245.  
  246.      ShowResult(result, heapRelation);
  247.    }
  248.  
  249.    AMendscan(scan);
  250. }
  251.  
  252. /* ----------------
  253.  *    DoBackwardScan
  254.  * ----------------
  255.  */
  256.  
  257. void FUNCTION
  258.    DoBackwardScan(indexRelation, heapRelation)
  259. Relation    indexRelation;
  260. Relation    heapRelation;
  261. {
  262.    IndexScanDesc        scan;
  263.    GeneralRetrieveIndexResult    result;
  264.  
  265.    puts("A complete reverse scan of the index reveals...");
  266.  
  267.    scan = RelationGetIndexScan(indexRelation, -1, 0, (ScanKey) NULL);
  268.  
  269.    for (;;) {
  270.       result = AMgettuple(scan, -1);
  271.  
  272.       if (!GeneralRetrieveIndexResultIsValid(result))
  273.      break;
  274.  
  275.      ShowResult(result, heapRelation);
  276.    }
  277.  
  278.    AMendscan(scan);
  279. }
  280.  
  281.  
  282. /* ----------------
  283.  *    DoSingleQualification
  284.  * ----------------
  285.  */
  286.  
  287. void FUNCTION
  288.    DoSingleQualification(indexRelation, heapRelation, entry)
  289. Relation    indexRelation;
  290. Relation    heapRelation;
  291. ScanKeyEntry    entry;
  292. {
  293.    IndexScanDesc        scan;
  294.    GeneralRetrieveIndexResult    result;
  295.  
  296.    QualificationKeyData[0] = *entry;
  297.  
  298.    ShowScanKeyEntry(&QualificationKeyData[0]);
  299.    puts("A scan of the index with one qualification reveals...");
  300.  
  301.    scan = RelationGetIndexScan(indexRelation, 0, 1,
  302.                    (ScanKey)QualificationKeyData);
  303.  
  304.    for (;;) {
  305.       result = AMgettuple(scan, 1);
  306.  
  307.       if (!GeneralRetrieveIndexResultIsValid(result))
  308.      break;
  309.  
  310.      ShowResult(result, heapRelation);
  311.    }
  312.  
  313.    AMendscan(scan);
  314. }
  315.  
  316.  
  317. /* ----------------
  318.  *    DoDoubleQualification
  319.  * ----------------
  320.  */
  321.  
  322. void FUNCTION
  323.    DoDoubleQualification(indexRelation, heapRelation, entry)
  324. Relation    indexRelation;
  325. Relation    heapRelation;
  326. ScanKeyEntry    entry;
  327. {
  328.    IndexScanDesc        scan;
  329.    GeneralRetrieveIndexResult    result;
  330.  
  331.    QualificationKeyData[1] = *entry;
  332.  
  333.    ShowScanKeyEntry(&QualificationKeyData[0]);
  334.    ShowScanKeyEntry(&QualificationKeyData[1]);
  335.    puts("A scan of the index with two qualifications reveals...");
  336.  
  337.    scan = RelationGetIndexScan(indexRelation, 0, 2,
  338.                    (ScanKey)QualificationKeyData);
  339.    for (;;) {
  340.       result = AMgettuple(scan, 1);
  341.  
  342.       if (!GeneralRetrieveIndexResultIsValid(result))
  343.      break;
  344.  
  345.      ShowResult(result, heapRelation);
  346.    }
  347.    AMendscan(scan);
  348. }
  349.  
  350. /* ----------------
  351.  *    DoMarkedQualification
  352.  * ----------------
  353.  */
  354.  
  355. void
  356. DoMarkedQualification(indexRelation, heapRelation, entry)
  357.    Relation    indexRelation;
  358.    Relation    heapRelation;
  359.    ScanKeyEntry    entry;
  360. {
  361.    IndexScanDesc        scan;
  362.    GeneralRetrieveIndexResult    result;
  363.    int                tuplesLeft;
  364.    bool                markIsSet;
  365.    int                whichWay;
  366.  
  367.    tuplesLeft = MarkedTuplesToProcess;
  368.    markIsSet = false;
  369.  
  370.    srandom((int)time(0));
  371.  
  372.    QualificationKeyData[0] = *entry;
  373.  
  374.    ShowScanKeyEntry(&QualificationKeyData[0]);
  375.    puts("A scan of the index reveals...");
  376.  
  377.    scan = RelationGetIndexScan(indexRelation, (bool) (0x1 & random()), 1,
  378.                    (ScanKey)QualificationKeyData);
  379.  
  380.    while (tuplesLeft > 0) {
  381.       if (!(random() & 0xf)) {
  382.      printf("RESTARTING SCAN\n");
  383.      AMrescan(scan, (bool) (0x1 & random()), (ScanKey)QualificationKeyData);
  384.      markIsSet = false;
  385.       }
  386.       if (!(random() & 0x3)) {
  387.      if (markIsSet) {
  388.         printf("RESTORING MARK\n");
  389.         AMrestrpos(scan);
  390.         if (!(0x1 & random())) {
  391.            markIsSet = false;
  392.         }
  393.      } else {
  394.         printf("SET MARK\n");
  395.         AMmarkpos(scan);
  396.         markIsSet = true;
  397.      }
  398.       }
  399.  
  400.       if ((random() & 0x1) == 0x1)
  401.      whichWay = -1;        /* backward */
  402.       else
  403.      whichWay = 1;        /* forward */
  404.  
  405.       result = AMgettuple(scan, whichWay);
  406.  
  407.       if (!GeneralRetrieveIndexResultIsValid(result)) {
  408.      puts("\t*NULL*");
  409.       } else {
  410.      ShowResult(result, heapRelation);
  411.       }
  412.  
  413.       tuplesLeft -= 1;
  414.    }
  415.    AMendscan(scan);
  416. }
  417.  
  418. /* ----------------------------------------------------------------
  419.  *    DoQualifiedScan
  420.  * ----------------------------------------------------------------
  421.  */
  422.  
  423. void
  424. DoQualifiedScan(indexRelation, heapRelation, operation, flags, returnType)
  425.    Relation    indexRelation;
  426.    Relation    heapRelation;
  427.    char        *operation;
  428.    uint16        flags;
  429.    ObjectId    returnType;
  430. {
  431.    ScanKeyEntry    scanKeyEntry;
  432.    extern ScanKeyEntry    GetScanKeyEntry();
  433.  
  434.    scanKeyEntry = GetScanKeyEntry(indexRelation, operation);
  435.  
  436.    /*
  437.     * Note: very dangerous to modify the reldesc, since it is cached.
  438.     */
  439.    scanKeyEntry->attributeNumber = 1;
  440.    scanKeyEntry->flags = flags;
  441.    scanKeyEntry->argument = ObjectIdGetDatum(returnType);
  442.  
  443.    switch (QualificationState) {
  444.    case UninitializedQualification:
  445.    case MarkedQualification:
  446.       QualificationState = SingleQualification;
  447.       DoSingleQualification(indexRelation, heapRelation,
  448.                 scanKeyEntry);
  449.       break;
  450.    case SingleQualification:
  451.       QualificationState = DoubleQualification;
  452.       DoDoubleQualification(indexRelation, heapRelation,
  453.                 scanKeyEntry);
  454.       break;
  455.    case DoubleQualification:
  456.       QualificationState = MarkedQualification;
  457.       DoMarkedQualification(indexRelation, heapRelation,
  458.                 scanKeyEntry);
  459.       break;
  460.    default:
  461.       fprintf(stderr, "testbtree: internal error!");
  462.       exitpg(255);
  463.    }
  464. }
  465.  
  466. void
  467. DoRuleLockInsertion(indexRelation)
  468.     Relation    indexRelation;
  469. {
  470.     BTreeSearchKey        v_left, v_right;
  471.     IndexTuple        itup_left, itup_right;
  472.     TupleDescriptor        idesc;
  473.     Datum            datum[1];
  474.     Boolean            null[1];
  475.     ScanKeyEntry        skeyEntry;
  476.     ScanKeyData        myLeftScanKey[1];
  477.     ScanKeyData        myRightScanKey[1];
  478.     BTreeInsertDataData    id_left, id_right;
  479.  
  480.     idesc = RelationGetTupleDescriptor(indexRelation);
  481.  
  482.     id_left.type  = BTREE_LEAF_INSERT_DATA | BTREE_RLOCK_L_INSERT_DATA;
  483.     id_right.type = BTREE_LEAF_INSERT_DATA | BTREE_RLOCK_R_INSERT_DATA;
  484.  
  485.     for (;;) {
  486.         char opname[10];
  487.         int opkey;
  488.  
  489.         /* clear out the input stream */
  490.         fseek(stdin, 0, 2);
  491.  
  492.         fprintf(stdout, "Enter left operator/key pair: ");
  493.         fflush(stdout);
  494.         if (scanf("%s%d", &opname[0], &opkey) != 2)
  495.             break;
  496.  
  497.         datum[0] = Int32GetDatum(opkey);
  498.         null[0] = ' ';
  499.  
  500.         itup_left = FormIndexTuple(1, idesc, datum, null);
  501.         id_left.indexTuple = itup_left;
  502.         id_left.size = psize(itup_left);
  503.  
  504.         skeyEntry = GetScanKeyEntry(indexRelation, opname);
  505.         myLeftScanKey[0].data[0] = *skeyEntry;
  506.         myLeftScanKey[0].data[0].attributeNumber = indexAttrNumber;
  507.         myLeftScanKey[0].data[0].argument = Int32GetDatum(opkey);
  508.  
  509.         v_left = RelationFormBTreeSearchKey(indexRelation,
  510.                             &id_left,
  511.                             1,
  512.                             &myLeftScanKey[0],
  513.                             NoMovementScanDirection,
  514.                             (ItemPointer) NULL);
  515.  
  516.         fprintf(stdout, "Enter right operator/key pair: ");
  517.         fflush(stdout);
  518.         scanf("%s%d", &opname[0], &opkey);
  519.  
  520.         datum[0] = Int32GetDatum(opkey);
  521.         null[0] = ' ';
  522.  
  523.         itup_right = FormIndexTuple(1, idesc, datum, null);
  524.         id_right.indexTuple = itup_right;
  525.         id_right.size = psize(itup_right);
  526.  
  527.         skeyEntry = GetScanKeyEntry(indexRelation, opname);
  528.         myRightScanKey[0].data[0] = *skeyEntry;
  529.         myRightScanKey[0].data[0].attributeNumber = indexAttrNumber;
  530.         myRightScanKey[0].data[0].argument = Int32GetDatum(opkey);
  531.  
  532.         v_right = RelationFormBTreeSearchKey(indexRelation,
  533.                              &id_right,
  534.                              1,
  535.                              &myRightScanKey[0],
  536.                              NoMovementScanDirection,
  537.                              (ItemPointer) NULL);
  538.  
  539.         BTreeRuleLockInsert(v_left, v_right);
  540.     }
  541. }
  542.  
  543. ScanKeyEntry
  544. GetScanKeyEntry(indexRelation, operation)
  545.     Relation    indexRelation;
  546.     char        *operation;
  547. {
  548.     StrategyNumber       strategyNumber;
  549.     IndexStrategy        indexStrategy;
  550.     StrategyMap          strategyMap;
  551.     ScanKeyEntry         scanKeyEntry;
  552.  
  553.     if (strcmp(operation, "<") == 0) {    
  554.         strategyNumber = BTreeLessThanStrategyNumber;
  555.     } else if (strcmp(operation, "<=") == 0) {
  556.         strategyNumber = BTreeLessThanOrEqualStrategyNumber;
  557.     } else if (strcmp(operation, "=") == 0) {
  558.         strategyNumber = BTreeEqualStrategyNumber;
  559.     } else if (strcmp(operation, ">=") == 0) {
  560.         strategyNumber = BTreeGreaterThanOrEqualStrategyNumber;
  561.     } else if (strcmp(operation, ">") == 0) {
  562.         strategyNumber = BTreeGreaterThanStrategyNumber;
  563.     } else {
  564.         fprintf(stderr, "testbtree: unknown operation \"%s\"\n",
  565.             operation);
  566.         return ((ScanKeyEntry) NULL);
  567.     }
  568.  
  569.     indexStrategy = RelationGetIndexStrategy(indexRelation);
  570.     strategyMap = IndexStrategyGetStrategyMap(indexStrategy,
  571.                           BTreeNumberOfStrategies, 1);
  572.     scanKeyEntry = StrategyMapGetScanKeyEntry(strategyMap, strategyNumber);
  573.  
  574.     if (!RegProcedureIsValid(scanKeyEntry->procedure)) {
  575.         fprintf(stderr, "testbtree: no procedure for strategy %d\n",
  576.             strategyNumber);
  577.  
  578.         return ((ScanKeyEntry) NULL);
  579.     }
  580.  
  581.     return (scanKeyEntry);
  582. }
  583.  
  584.  
  585. /* ----------------------------------------------------------------
  586.  *                 TestMain
  587.  * ----------------------------------------------------------------
  588.  */
  589.  
  590. void FUNCTION
  591. TestMain()
  592. {
  593.    static NameData    heapNameData;
  594.    static NameData     indexNameData;
  595.           Relation    indexRelation;
  596.           Relation    heapRelation;
  597.    static int            beenHere = 0;
  598.       Portal    portal;
  599.  
  600.  
  601.    Relation        AMopenr();    /* XXX */
  602.  
  603.  
  604.    portal = CreatePortal("<blank>");
  605.    StartTransactionCommand(portal);
  606.  
  607.    if (beenHere == 0) {
  608.       char *result;
  609.       bool newIndex;
  610.       bool done;
  611.  
  612.       /* discard any stuff on the input stream */
  613.       fseek(stdin, 0, 2);
  614.  
  615.       fprintf(stdout, "Relation: ");
  616.       fflush(stdout);
  617.  
  618.       if ((result = gets(&heapNameData.data[0])) == (char *) NULL) {
  619.      elog(NOTICE, "testbtree: no heap specified");
  620.      exitpg(0);
  621.       }
  622.  
  623.       fprintf(stdout, "Index name: ");
  624.       fflush(stdout);
  625.  
  626.       if ((result = gets(&indexNameData.data[0])) == (char *) NULL) {
  627.      elog(NOTICE, "testbtree: no index specified");
  628.      exitpg(0);
  629.       }
  630.  
  631.       do {
  632.      char buf[20];
  633.  
  634.      fprintf(stdout, "Is this a new index? (y/n) ");
  635.      fflush(stdout);
  636.  
  637.      result = gets(&buf[0]);
  638.  
  639.      if (result != (char *) NULL) {
  640.         if (strcmp(result, "y") == 0) {
  641.            newIndex = true;
  642.            done = true;
  643.         } else if (strcmp(result, "n") == 0) {
  644.            newIndex = false;
  645.            done = true;
  646.         } else {
  647.            fprintf(stdout, "*** y or n only ***\n");
  648.            done = false;
  649.         }
  650.      } else {
  651.         fprintf(stdout, "*** y or n only ***\n");
  652.         done = false;
  653.      }
  654.       } while (!done);
  655.  
  656.       fprintf(stdout, "Attribute number for index: ");
  657.       fflush(stdout);
  658.  
  659.       if (scanf("%hd", &indexAttrNumber) != 1) {
  660.      elog(NOTICE, "testbtree: attribute incorrectly specified");
  661.      exitpg(0);
  662.       }
  663.  
  664.       if (newIndex) {
  665.      fprintf(stdout, "Operator class (421 = int2, 426 = int4): ");
  666.      fflush(stdout);
  667.  
  668.          if (scanf("%hd", &indexAttrClass) != 1) {
  669.         elog(NOTICE, "testbtree: class incorrectly specified");
  670.         exitpg(0);
  671.          }
  672.      if (indexAttrClass != 421 && indexAttrClass != 426) {
  673.         elog(NOTICE, "No such class, assuming int2.");
  674.         indexAttrClass = 426;
  675.      }
  676.  
  677.      fseek(stdin, 0, 2);
  678.  
  679.      beenHere = 1;
  680.  
  681.      DoCreateIndex(&heapNameData, &indexNameData,
  682.                indexAttrNumber, indexAttrClass);
  683.  
  684.       }
  685.  
  686.       CommitTransactionCommand();
  687.       StartTransactionCommand(portal);
  688.  
  689.       beenHere = 2;
  690.  
  691.    } else if (beenHere == 1) {
  692.       elog(NOTICE, "testbtree: %s relation may exist--continuing!",
  693.        indexNameData.data);
  694.       beenHere = 2;
  695.  
  696.    } else if (beenHere > 1) {
  697.       elog(FATAL, "testbtree: giving up!");
  698.    }
  699.  
  700.    indexRelation = AMopenr(indexNameData.data);    /* XXX */
  701.    DoRuleLockInsertion(indexRelation);
  702.    AMclose(indexRelation);
  703.  
  704.    QualificationState = UninitializedQualification;
  705.  
  706.    indexRelation = AMopenr(indexNameData.data);    /* XXX */
  707.    heapRelation = RelationNameOpenHeapRelation(heapNameData.data);
  708.  
  709.    RelationSetLockForRead(heapRelation);
  710.  
  711.    DoBTreeBrowse(indexRelation, heapRelation);
  712.    DoForwardScan(indexRelation, heapRelation);
  713.    DoBackwardScan(indexRelation, heapRelation);
  714.  
  715.    for (;;) {
  716.       int        status;
  717.       NameData        operatorNameData;
  718.       ObjectId        returnType;
  719.  
  720.       puts("\nPlease enter an operator and an integer value");
  721.  
  722.       fseek(stdin, 0, 2);    /* discard any stuff on the input stream */
  723.       status = scanf("%s%d", &(operatorNameData), &returnType);
  724.  
  725.       if (status <= 0) {
  726.      break;
  727.       } else if (status != 2) {
  728.      elog(NOTICE, "testbtree: improper qualification specified");
  729.      exitpg(0);
  730.       }
  731.  
  732.       DoQualifiedScan(indexRelation, heapRelation, &operatorNameData,
  733.               0, returnType);
  734.    }
  735.  
  736.    RelationCloseHeapRelation(heapRelation);
  737.    RelationCloseIndexRelation(indexRelation);
  738.  
  739.    puts("\nDone!");
  740.    CommitTransactionCommand();
  741.    exitpg(0);
  742. }
  743.